#include "Server.h"
#include <iostream>
#include <unistd.h>
#include <string.h>

const std::string Server::DEFAULT_ADDR[3]  = {
    "127.0.0.1:5000",
    "127.0.0.1:5001",
    "127.0.0.1:5002" 
};

Server::Server(int server_id) {
    if (server_id < 0 || server_id >= 3) {
        std::cerr << "Invalid server ID" << std::endl;
        exit(EXIT_FAILURE);
    }

    id = server_id;

    // 创建socket，使用UDP协议通讯
    sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0) {
        std::cerr << "Error creating socket" << std::endl;
    }

    // 设置地址结构
    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = INADDR_ANY;
    addr.sin_port = htons(extractPort(DEFAULT_ADDR[id]));

    // 绑定地址到socket
    if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
        std::cerr << "Error binding socket" << std::endl;
        close(sock);
        exit(EXIT_FAILURE);
    }

    /*
    // 开始监听，允许最多同时排队3个
    if (listen(sock, 3) < 0) {
        std::cerr << "Error listening on socket" << std::endl;
        close(sock);
        exit(EXIT_FAILURE);
    }
    */

    std::cout << "Server " << id << " is starting to listen on address: " << DEFAULT_ADDR[id] << std::endl;
}

Server::~Server() {
    close(sock);
}

void Server::send(int to_id, std::string message) {
    // 设置接收方的地址结构
    struct sockaddr_in to_addr;
    to_addr.sin_family = AF_INET;
    to_addr.sin_port = htons(extractPort(DEFAULT_ADDR[to_id]));
    to_addr.sin_addr.s_addr = INADDR_ANY;

    // 发送message到to_addr
    sendto(sock, message.c_str(), message.size(), 0, (struct sockaddr*)&to_addr, sizeof(to_addr));
}

std::string Server::read() {
    // 声明消息空间
    char message[1024];

    // 声明接收地址结构
    struct sockaddr_in from_addr;
    socklen_t len = sizeof(from_addr);

    // 接收消息并为消息末尾添加结束符
    int n = recvfrom(sock, message, 1024, 0, (struct sockaddr*)&from_addr, &len);
    message[n] = '\0';

    // 解析from_addr的信息
    char from_ip[INET_ADDRSTRLEN]; //INET_ADDRSTRLEN 是一个常量，用于指定存储 IPv4 地址的字符串所需的最小缓冲区大小（通常为 16 字节）
    inet_ntop(AF_INET, &(from_addr.sin_addr), from_ip, INET_ADDRSTRLEN);  // 将二进制格式的 IP 地址转换为字符串格式
    std::cout << "Server " << id << " received message from " << from_ip << ":" << ntohs(from_addr.sin_port) << std::endl;

    return message;
}

/* TCP
void Server::send(int to_id, std::string message) {
    // 创建接收方的socket
    int to_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (to_sock < 0) {
        std::cerr << "Error creating socket" << std::endl;
    }

    // 设置接收方的地址结构
    struct sockaddr_in to_addr;
    to_addr.sin_family = AF_INET;
    to_addr.sin_port = htons(extractPort(DEFAULT_ADDR[to_id]));
    to_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

    // 将socket连接到远程地址
    if (connect(to_sock, (struct sockaddr*)&to_addr, sizeof(to_addr)) < 0) {
        std::cerr << "Error connecting to server " << to_id << std::endl;
        close(to_sock);
        exit(EXIT_FAILURE);
    }

    // 向接收方发送消息
    if (write(to_sock, message.c_str(), message.size()) < 0) {
        std::cerr << "Error writing to socket" << std::endl;
    }

    close(to_sock);
}

std::string Server::read() {
    // 声明发送方socket
    int from_sock;

    // 声明发送方地址结构
    struct sockaddr_in from_addr;
    socklen_t from_len = sizeof(from_addr);
    
    // 从监听套接字队列中取出一个连接请求，并创建一个新的socket，该套接字用于通信
    if (from_sock = accept(sock, (struct sockaddr*)&from_addr, &from_len) < 0) {
        std::cerr << "Error accepting connection" << std::endl;
        close(from_sock);
        exit(EXIT_FAILURE);
    }

    char message[1024];
    memset(message, 0, sizeof(message));
    if (recv(from_sock, message, sizeof(message), 0) < 0) {
        std::cerr << "Error receiving message" << std::endl;
        close(from_sock);
        exit(EXIT_FAILURE);
    }

    close(from_sock);

    return message;
}


void Server::run() {
    while (true) {
        std::string message = read();
        std::cout << "received message: " << message << std::endl;
    }
}
*/

int Server::extractPort(const std::string &address) {
    std::string::size_type pos = address.find(':');
    if (pos == std::string::npos) {
        std::cerr << "Invalid address format" << std::endl;
        exit(EXIT_FAILURE);
    }
    return std::stoi(address.substr(pos + 1));
}